// 创建着色器函数
function createShader(gl, type, source) {
  // 创建着色器对象
  const shader = gl.createShader(type);
  // 将着色器源代码赋值给着色器对象
  gl.shaderSource(shader, source);

  // 编译着色器
  gl.compileShader(shader);
  // 检查着色器是否编译成功
  if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
    // 如果编译失败，抛出错误
    throw new Error(gl.getShaderInfoLog(shader));
  }

  // 返回着色器对象
  return shader;
}

// 导出一个函数，用于创建一个程序
export function createProgram(gl, vertexSource, fragmentSource) {
  // 创建一个程序
  const program = gl.createProgram();

  // 创建顶点着色器
  const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexSource);
  // 创建片元着色器
  const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentSource);

  // 将顶点着色器和片元着色器附加到程序上
  gl.attachShader(program, vertexShader);
  gl.attachShader(program, fragmentShader);

  // 链接程序
  gl.linkProgram(program);
  // 如果链接失败，抛出错误
  if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
    throw new Error(gl.getProgramInfoLog(program));
  }

  // 创建一个包装器，用于存储程序和属性、变量的位置
  const wrapper = { program: program };

  // 获取程序中活动的属性数量
  const numAttributes = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES);
  // 遍历属性，获取属性的位置
  for (let i = 0; i < numAttributes; i++) {
    const attribute = gl.getActiveAttrib(program, i);
    wrapper[attribute.name] = gl.getAttribLocation(program, attribute.name);
  }
  // 获取程序中活动的变量数量
  const numUniforms = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS);
  // 遍历变量，获取变量的位置
  for (let i = 0; i < numUniforms; i++) {
    const uniform = gl.getActiveUniform(program, i);
    wrapper[uniform.name] = gl.getUniformLocation(program, uniform.name);
  }

  // 返回包装器
  return wrapper;
}

// 导出一个函数，用于创建纹理
export function createTexture(gl, filter, data, width, height) {
  // 创建一个纹理对象
  const texture = gl.createTexture();
  // 绑定纹理对象
  gl.bindTexture(gl.TEXTURE_2D, texture);
  // 设置纹理的环绕方式为边缘环绕
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
  // 设置纹理的缩小和放大过滤方式
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, filter);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, filter);
  // 如果传入的数据是Uint8Array类型，则使用texImage2D方法将数据传入纹理对象
  if (data instanceof Uint8Array) {
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);
  } else {
    // 否则，使用texImage2D方法将图像数据传入纹理对象
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, data);
  }
  // 解绑纹理对象
  gl.bindTexture(gl.TEXTURE_2D, null);
  // 返回纹理对象
  return texture;
}

// 导出一个函数，用于绑定纹理
export function bindTexture(gl, texture, unit) {
  // 激活纹理单元
  gl.activeTexture(gl.TEXTURE0 + unit);
  // 绑定纹理
  gl.bindTexture(gl.TEXTURE_2D, texture);
}

// 导出一个函数，用于创建缓冲区
export function createBuffer(gl, data) {
  // 创建一个缓冲区对象
  const buffer = gl.createBuffer();
  // 绑定缓冲区对象到目标
  gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
  // 向缓冲区对象写入数据
  gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
  // 返回缓冲区对象
  return buffer;
}

// 导出一个函数，用于绑定属性
export function bindAttribute(gl, buffer, attribute, numComponents) {
  // 绑定缓冲区
  gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
  // 启用属性数组
  gl.enableVertexAttribArray(attribute);
  // 设置属性数组的数据格式
  gl.vertexAttribPointer(attribute, numComponents, gl.FLOAT, false, 0, 0);
}

// 导出一个函数，用于绑定帧缓冲区和纹理
export function bindFramebuffer(gl, framebuffer, texture) {
  // 绑定帧缓冲区
  gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
  // 如果有纹理，则将纹理绑定到帧缓冲区的颜色附件上
  if (texture) {
    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
  }
}
